﻿using System.Collections.Generic;
using ShevaEngine.Core.Modules.Graphics;
using ShevaEngine.Core.Modules.Models;
using Microsoft.Xna.Framework.Graphics;
using ShevaEngine.Core.Modules.Materials;
using Microsoft.Xna.Framework;
using ShevaEngine.Core.Interfaces;

namespace ShevaEngine.Core.Modules.Scenes
{
    /// <summary>
    /// Graphics scene object.
    /// </summary>
    public class GraphicsSceneObject : SceneObject
    {
        /// <summary>Graphics scene object node.</summary>
        public List<GraphicsSceneObjectNode> GraphicsSceneObjectNodes;
        /// <summary>Sheva model.</summary>
        private ShevaModel Model;

        /// <summary>
        /// Constructor.
        /// </summary>
        public GraphicsSceneObject(ShevaModel model)
            : base()
        {
            this.Model = model;
        }

        /// <summary>
        /// Constructor.
        /// </summary>
        public GraphicsSceneObject(ShevaModel model, Matrix transformation)
            : base(transformation)
        {
            this.Model = model;
        }

        /// <summary>
        /// Method creates draw calls.
        /// </summary>
        /// <param name="buffersManager"></param>
        internal void CreateDrawCalls(GraphicsBuffersManager buffersManager)
        {
            this.GraphicsSceneObjectNodes = new List<GraphicsSceneObjectNode>();

            foreach (ShevaMesh mesh in Model.Meshes)
                this.GraphicsSceneObjectNodes.Add(this.CreateDrawCalls(buffersManager, mesh));
        }

        /// <summary>
        /// Method creates mesh scene node.
        /// </summary>
        /// <param name="buffersManager"></param>
        /// <param name="mesh"></param>
        /// <returns></returns>
        internal GraphicsSceneObjectNode CreateDrawCalls(GraphicsBuffersManager buffersManager, ShevaMesh mesh)
        {
            GraphicsSceneObjectTransformation newNode = new GraphicsSceneObjectTransformation();

            newNode.TransformationMatrix = mesh.Transform;

            foreach (ShevaModelGeometry geometry in mesh.Geometries)
                newNode.Children.Add(this.CreateDrawCalls(buffersManager, geometry));

            return newNode;
        }

        /// <summary>
        /// Method creates geometry scene node.
        /// </summary>
        /// <param name="buffersManager"></param>
        /// <param name="geometry"></param>
        /// <returns></returns>
        internal GraphicsSceneObjectNode CreateDrawCalls(GraphicsBuffersManager buffersManager, ShevaModelGeometry geometry)
        {
            GraphicsSceneObjectDrawCallNode newNode = new GraphicsSceneObjectDrawCallNode();
            
            newNode.DrawCall = (IDrawCall)geometry.Clone();
            newNode.DrawCallKey = new DrawCallKey(
                MaterialManager.Instance.GetMaterialID(geometry.MaterialParameters.Name),
                TextureManager.Instance.GetTextureStateId(geometry.MaterialParameters.Textures), 
                0, 
                buffersManager.GetBuffersID(geometry.VertexBuffer, geometry.IndexBuffer));

            return newNode;
        }

        /// <summary>
        /// Override Add in rendering pipeline method.
        /// </summary>
        /// <param name="renderingPipeline"></param>
        public override void AddInRenderingPipeline(RenderingPipeline renderingPipeline)
        {
            for (int i = 0; i < this.GraphicsSceneObjectNodes.Count; i++)
                this.GraphicsSceneObjectNodes[i].AddInRenderingPipeline(renderingPipeline, this.WorldMatrix);
        }
    }
}
